package com.bigfans.cartservice.service.impl;

import com.bigfans.cartservice.api.clients.InventoryServiceClient;
import com.bigfans.cartservice.api.clients.PricingServiceClient;
import com.bigfans.cartservice.dao.CartItemDAO;
import com.bigfans.cartservice.exception.ProductOffSaleException;
import com.bigfans.cartservice.exception.StockInsufficientException;
import com.bigfans.cartservice.model.*;
import com.bigfans.cartservice.service.CartService;
import com.bigfans.cartservice.service.ProductService;
import com.bigfans.cartservice.service.ProductSpecService;
import com.bigfans.framework.Applications;
import com.bigfans.framework.CurrentUser;
import com.bigfans.framework.dao.BaseServiceImpl;
import com.bigfans.framework.utils.CollectionUtils;
import com.bigfans.model.dto.cart.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;

/**
 * 购物车服务类
 *
 * @author lichong
 */
@Service(CartServiceImpl.BEAN_NAME)
public class CartServiceImpl extends BaseServiceImpl<CartItem> implements CartService {

    public static final String BEAN_NAME = "cartService";

    @Autowired
    private ProductService productService;
    @Autowired
    private ProductSpecService productSpecService;
    @Autowired
    private PricingServiceClient pricingServiceClient;
    @Autowired
    private InventoryServiceClient inventoryServiceClient;

    private CartItemDAO cartItemDAO;

    @Autowired
    public CartServiceImpl(CartItemDAO cartItemDAO) {
        super(cartItemDAO);
        this.cartItemDAO = cartItemDAO;
    }

    /**
     * 获取用户的购物车信息
     *
     * @param userId
     * @return
     * @throws Exception
     */
    public Cart myCart(String userId) throws Exception {
        return myCart(userId, null, null);
    }

    @Override
    @Transactional(readOnly = true)
    public Cart cartSummary(String userId, Long limit) throws Exception {
        List<CartItem> cartItems = cartItemDAO.listByUser(userId, 0L, limit);
        Cart cart = this.populateCart(cartItems);
        return cart;
    }

    @Override
    @Transactional(readOnly = true)
    public Cart myCart(String userId, Long start, Long pagesize) throws Exception {
        List<CartItem> cartItems = cartItemDAO.listByUser(userId, start, pagesize);
        Cart cart = this.populateCart(cartItems);
        return cart;
    }

    @Override
    @Transactional(readOnly = true)
    public Cart populateCart(List<CartItem> cartItems) throws Exception {
        Cart cart = new Cart();
        if (CollectionUtils.isEmpty(cartItems)) {
            return cart;
        }
        CartPricingDto cartPricingDto = new CartPricingDto();
        cartPricingDto.setUserId(cartItems.get(0).getUserId());
        for (CartItem cartItem : cartItems) {
            CartItemDto itemDto = new CartItemDto(cartItem.getProdId(), cartItem.getQuantity());
            cartPricingDto.addCartItem(itemDto);
        }
        CurrentUser currentUser = Applications.getCurrentUser();
        CartPricingResultDto calculateResultDto = pricingServiceClient.calculateCart(currentUser, cartPricingDto);

        for (CartItem item : cartItems) {

            String prodId = item.getProdId();
            // 获取商品信息
            Product product = productService.getDetailById(prodId);
            item.setProdName(product.getName());
            item.setProdImg(product.getImagePath());
            item.setSpecList(product.getSpecList());
            item.setWeight(product.getWeight());

            CartItemPricingResultDto pricingDto = calculateResultDto.getPrice(item.getProdId());
            item.setOriginalPrice(pricingDto.getOriginalPrice());
            item.setPrice(pricingDto.getPrice());
            item.setOriginalSubTotal(pricingDto.getOriginalSubTotal());
            item.setSubTotal(pricingDto.getSubtotal());


            List<CartItemPromotionDto> promotions = calculateResultDto.getPromotion(prodId);
            if (CollectionUtils.isNotEmpty(promotions)) {
                List<Promotion> promotionList = new ArrayList<>();
                promotions.forEach((promotionDto) -> {
                    Promotion promotion = new Promotion();
                    promotion.setId(promotionDto.getPromotionId());
                    promotion.setName(promotionDto.getPromotionName());
                    promotion.setSelectable(promotionDto.isSelectable());
                    promotion.setSelected(promotionDto.isSelected());
                    promotionList.add(promotion);
                });
                item.setPromotionList(promotionList);
            }

            List<CartItemCouponDto> coupons = calculateResultDto.getCoupon(prodId);
            if (CollectionUtils.isNotEmpty(coupons)) {
                List<Coupon> couponList = new ArrayList<>();
                coupons.forEach((couponDto) -> {
                    Coupon coupon = new Coupon();
                    coupon.setName(couponDto.getCouponName());
                    coupon.setSelectable(couponDto.isSelectable());
                    coupon.setSelected(couponDto.isSelected());
                    couponList.add(coupon);
                });
                item.setCouponList(couponList);
            }
        }
        cart.setItems(cartItems);
        return cart;
    }

    /**
     * 合并购物车
     *
     * @throws Exception
     */
    public void mergeMyCart(String userId, Cart tempCart) throws Exception {
        Cart dbCart = myCart(userId);
        List<CartItem> tempItems = tempCart.getItems();
        if (CollectionUtils.isEmpty(tempItems)) {
            return;
        }
        Map<String, CartItem> dbitemMap = new HashMap<String, CartItem>();
        for (CartItem dbItem : dbCart.getItems()) {
            dbitemMap.put(dbItem.getProdId(), dbItem);
        }
        List<CartItem> itemToCreate = new ArrayList<CartItem>();
        for (CartItem tempItem : tempItems) {
            CartItem civo = dbitemMap.get(tempItem.getProdId());
            // 如果db中不存在,那么创建一条记录,否则更新购买数量
            if (civo == null) {
                tempItem.setUserId(userId);
                itemToCreate.add(tempItem);
            } else {
                // 更新购买数量为临时购物车中的数量
                civo.setQuantity(tempItem.getQuantity());
                update(civo);
            }
        }
        if (!CollectionUtils.isEmpty(itemToCreate)) {
            batchCreate(itemToCreate);
        }
    }

    /**
     * 添加购物项
     *
     * @param userId
     * @throws Exception
     */
    @Transactional
    public void addItem(String userId, String pid, Integer quantity) throws Exception {
        // 添加购物项
        Long count = cartItemDAO.countByUser(userId, pid);
        if (count > 0) {
            // 如果已经添加商品到购物车，增加数量
            cartItemDAO.increaseByUser(userId, pid, quantity);
        } else {
            // 创建一条记录
            CartItem cartItem = new CartItem();
            cartItem.setUserId(userId);
            cartItem.setProdId(pid);
            cartItem.setQuantity(quantity);
            cartItem.setIsSelected(true);
            super.create(cartItem);
        }
    }

    /**
     * 移除购物项
     *
     * @param userId
     * @param id     购物车项id
     * @throws Exception
     */
    @Transactional
    public void removeItem(String userId, String id) throws Exception {
        cartItemDAO.deleteMyItemsById(userId, new String[]{id});
    }

    @Transactional
    public void removeItems(String userId, String[] ids) throws Exception {
        cartItemDAO.deleteMyItemsById(userId, ids);
    }

    @Transactional
    public void removeCart(String userId) throws Exception {
        cartItemDAO.deleteMyItemsById(userId, null);
    }

    @Override
    public void removeSelectedItems(String userId) throws Exception {
        cartItemDAO.deleteSelectedItems(userId);
    }

    @Transactional
    public void updateQuantity(String uid, String prodId, int quantity) throws Exception {
        try {
            CompletableFuture<Integer> future = inventoryServiceClient.getSurplusStock(prodId);
            CartItem cartItem = cartItemDAO.loadByUser(uid, prodId);
            if (!cartItem.isProductOnSale()) {
                throw new ProductOffSaleException("该商品已经下架");
            }

            // 查询库存,如果库存不足抛出异常
            Integer stock = future.get();
            if (stock == null || stock < quantity) {
                throw new StockInsufficientException("该商品库存不足");
            }

            // 更新购买数量
            CartItem example = new CartItem();
            example.setId(cartItem.getId());
            example.setQuantity(quantity);
            super.update(example);
        } catch (Exception e) {
            throw new Exception(e);
        }
    }

    @Override
    public Integer sumMyCart(String userId) throws Exception {
        Long sum = cartItemDAO.sumByUser(userId);
        return sum == null ? 0 : sum.intValue();
    }

    @Override
    public Integer countByProduct(String uid, String pid) throws Exception {
        return null;
    }

    @Override
    @Transactional(readOnly = true)
    public List<CartItem> getSelectedItems(String userId) throws Exception {
        return cartItemDAO.getItems(userId, true);
    }

    @Override
    public List<CartItem> getItems(String userId) throws Exception {
        return cartItemDAO.getItems(userId, false);
    }

    @Override
    @Transactional
    public void select(String userId, String productId) throws Exception {
        cartItemDAO.changeItemSelectStatus(userId, productId, true);
    }

    @Override
    @Transactional
    public void selectAll(String userId) throws Exception {
        cartItemDAO.changeAllItemsSelectStatus(userId, true);
    }

    @Override
    @Transactional
    public void cancel(String userId, String productId) throws Exception {
        cartItemDAO.changeItemSelectStatus(userId, productId, false);
    }

    @Override
    @Transactional
    public void cancelAll(String userId) throws Exception {
        cartItemDAO.changeAllItemsSelectStatus(userId, false);
    }

}
